home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 44 / Amiga Format CD44 (1999-08-26)(Future Publishing)(GB)(Track 1 of 3)[!][issue 1999-10].iso / -in_the_mag- / workbench / netkeys / src / netkeys.e < prev   
Text File  |  1999-07-28  |  8KB  |  297 lines

  1. -> NetKeys v1.1 by Kyzer/CSG
  2. -> transmits key and mouse input through network connection.
  3.  
  4. OPT PREPROCESS, OSVERSION=37
  5.  
  6. MODULE 'commodities', 'devices/inputevent', 'devices/pronet', 'dos/dos',
  7.        'exec/errors', 'exec/io', 'exec/nodes', 'exec/ports',
  8.        'libraries/commodities', '*args'
  9.  
  10. RAISE "CX"   IF CreateCxObj()=NIL,
  11.       "LIB"  IF OpenLibrary()=NIL,
  12.       "MEM"  IF CreateMsgPort()=NIL,
  13.       "MEM"  IF CreateIORequest()=NIL
  14.  
  15. #define VERSION '$VER: NetKeys 1.1 (16.11.98)'
  16.  
  17.  
  18. CONST NETKEYS_PORT = 10350
  19. ENUM EVT_HOTKEY, EVT_INPUT
  20.  
  21. #define PORTSIG(port)  (Shl(1, port.sigbit))
  22. #define APTR           PTR TO LONG
  23.  
  24. #define TEMPLATE \
  25.  'MOUSE/S,CX_HOTKEY,CX_PRIORITY=CX_PRI/N,CX_ACTIVATE/S,MACHINE/N'
  26.  
  27. OBJECT myargs
  28.   usemouse    -> should netkeys also send mouse events? (default FALSE)
  29.   cx_hotkey   -> hotkey to activate/deactivate netkeys (default 'ctrl alt k')
  30.   cx_pri:APTR -> alternative CX priority (default 120)
  31.   cx_activate -> should netkeys start running on bootup? (default FALSE)
  32.   unit:APTR   -> ProNET machine number/device unit to use (default 0)
  33. ENDOBJECT
  34.  
  35. DEF args:PTR TO myargs,
  36.     cxport=NIL:PTR TO mp, broker=NIL, hotkey, keys, mouse, enabled,
  37.     netport=NIL:PTR TO mp, netio=NIL:PTR TO pnrequest, devport=NIL, open=-1
  38.  
  39. PROC main() HANDLE
  40.   DEF rdargs=NIL, ioerr
  41.  
  42.   VOID VERSION
  43.  
  44.   -> set up all the default arguments (as listed above) and parse the
  45.   -> arguments from CLI or WB
  46.   args := [FALSE, 'ctrl alt k', [120], FALSE, [0]]
  47.   IF (rdargs := readargs(TEMPLATE, args, wbmessage))=NIL THEN Raise("ARGS")
  48.  
  49.   -> install a commodities broker to recieve commodity commands and act
  50.   -> as the base of our input stream processing
  51.   install_broker(args.cx_pri[])
  52.  
  53.   -> open our connection to the ProNET network device
  54.   open_net(args.unit[], NETKEYS_PORT)
  55.  
  56.  
  57.   -> Install filters - one accepts only the hotkey (sends EVT_HOTKEY messages),
  58.   -> one grabs all keys, sends them to us (EVT_INPUT messages) and deletes
  59.   -> them, another optional one grabs all mouse-movements, and does likewise.
  60.  
  61.   hotkey := install_filter(args.cx_hotkey, EVT_HOTKEY, 2)
  62.   IF CxObjError(hotkey) THEN Raise("CXK") -> if invalid hotkey
  63.  
  64.   keys := install_filter(NIL, EVT_INPUT, 1)
  65.   SetFilterIX(keys, [IX_VERSION, IECLASS_RAWKEY, 0,0,0,0,0]:inputxpression)
  66.  
  67.   IF args.usemouse
  68.     mouse := install_filter(NIL, EVT_INPUT, 0)
  69.     SetFilterIX(mouse, [IX_VERSION, IECLASS_RAWMOUSE, 0,0,0,0,0]:inputxpression)
  70.   ENDIF
  71.  
  72.   -> start up our commodity, possibly start input-grabbing too
  73.   enable_netkeys(args.cx_activate)
  74.  
  75.   mainloop()
  76.  
  77. EXCEPT DO
  78.   ioerr := IoErr()
  79.  
  80.   -> disconnect from network
  81.   close_net()
  82.  
  83.   -> remove our commodity
  84.   remove_broker()
  85.  
  86.   IF rdargs THEN FreeArgs(rdargs)
  87.  
  88.   SELECT exception
  89.   CASE "MEM";  msg(error(ERROR_NO_FREE_STORE))
  90.   CASE "NET";  msg(neterror(exceptioninfo))
  91.   CASE "CX";   msg('Error creating NetKeys commodity')
  92.   CASE "CXK";  msg('Invalid hotkey')
  93.   CASE "LIB";  msg('Error opening commodities.library')
  94.  
  95.   DEFAULT;     IF ioerr THEN msg(error(ioerr))
  96.   ENDSELECT
  97. ENDPROC
  98.  
  99.  
  100. CONST CTRLSIGS = SIGBREAKF_CTRL_C OR SIGBREAKF_CTRL_D OR SIGBREAKF_CTRL_E 
  101.  
  102. PROC mainloop()
  103.   DEF sigs, m, id, type, evt:inputevent, quit=FALSE
  104.  
  105.   REPEAT
  106.     sigs := Wait(CTRLSIGS OR PORTSIG(cxport) OR PORTSIG(netport))
  107.  
  108.     WHILE m := GetMsg(cxport)
  109.       type := CxMsgType(m)
  110.       id   := CxMsgID(m)
  111.  
  112.       SELECT type
  113.       CASE CXM_IEVENT
  114.         CopyMem(CxMsgData(m), evt, SIZEOF inputevent)
  115.         ReplyMsg(m)
  116.  
  117.         SELECT id
  118.         CASE EVT_INPUT;  send_data(evt, SIZEOF inputevent)
  119.         CASE EVT_HOTKEY; enable_netkeys(IF enabled THEN FALSE ELSE TRUE)
  120.         ENDSELECT
  121.  
  122.       CASE CXM_COMMAND
  123.         ReplyMsg(m)
  124.  
  125.         -> standard Commodities behaviour
  126.         SELECT id
  127.         CASE CXCMD_DISABLE; ActivateCxObj(broker, FALSE)
  128.         CASE CXCMD_ENABLE;  ActivateCxObj(broker, TRUE)
  129.         CASE CXCMD_KILL;    quit := TRUE
  130.         CASE CXCMD_UNIQUE;  quit := TRUE
  131.         ENDSELECT
  132.       ENDSELECT
  133.     ENDWHILE
  134.  
  135.     -> throw away anything that arrives at our network port
  136.     -> as we do not care to recieve any data
  137.     clear_port(netport)
  138.  
  139.     -> standard commodity behaviour
  140.     IF sigs AND SIGBREAKF_CTRL_C THEN quit := TRUE
  141.     IF sigs AND SIGBREAKF_CTRL_D THEN ActivateCxObj(broker, FALSE)
  142.     IF sigs AND SIGBREAKF_CTRL_E THEN ActivateCxObj(broker, TRUE)
  143.  
  144.   UNTIL quit
  145. ENDPROC
  146.  
  147.  
  148.  
  149.  
  150. ->-----------------------------------------------------------------------------
  151.  
  152. -> install_broker(): create a cxport and install the base commodity object
  153. PROC install_broker(priority)
  154.   -> create a port to recieve CXMessages
  155.   cxport := CreateMsgPort()
  156.  
  157.   -> install a broker in the commodities network
  158.   -> the broker says we have no 'user interface', and we must not be
  159.   -> run more than once. If we are, the other copy of us is notified,
  160.   -> and will quit itself.
  161.  
  162.   cxbase := OpenLibrary('commodities.library', 37)
  163.  
  164.   broker := CxBroker([
  165.     NB_VERSION, 0,
  166.     'NetKeys',
  167.     'ProNET netkeys/netmouse',
  168.     'Use keyboard/mouse over network',
  169.     NBU_UNIQUE OR NBU_NOTIFY, 0, priority, 0, cxport, 0
  170.   ]:newbroker, NIL)
  171.  
  172.   IF broker = NIL THEN Raise() -> silent error if we can't make a broker
  173. ENDPROC
  174.  
  175.  
  176. -> install_filter(expression, event_type, pri): install filter which
  177. -> sends all input matching the expression string to our cxport, with
  178. -> type event_type, then deletes the input from the input stream.
  179. ->
  180. PROC install_filter(expression, event_type, priority)
  181.   DEF filter
  182.  
  183.   -> attach a new filter to our broker with certain priority
  184.   AttachCxObj(broker, filter := CxFilter(expression))
  185.   SetCxObjPri(filter, priority)
  186.  
  187.   -> our filter will send us then delete any matching input
  188.   AttachCxObj(filter, CxSender(cxport, event_type))
  189.   AttachCxObj(filter, CxTranslate(NIL))
  190. ENDPROC filter
  191.  
  192.  
  193. -> remove_broker(): remove our commodity from the system
  194. PROC remove_broker()
  195.   -> remove all our CXObjects and their broker
  196.   IF broker THEN DeleteCxObjAll(broker)
  197.  
  198.   -> close commodities library
  199.   CloseLibrary(cxbase)
  200.  
  201.   -> throw away any remaining CXMessages at our cxport, then delete it
  202.   IF cxport
  203.     clear_port(cxport)
  204.     DeleteMsgPort(cxport)
  205.   ENDIF
  206. ENDPROC
  207.  
  208.  
  209. -> enable_netkeys(state): TRUE enables netkeys/netmouse, FALSE disables it.
  210. PROC enable_netkeys(state)
  211.   enabled := state
  212.  
  213.   IF args.usemouse THEN ActivateCxObj(mouse, state)
  214.   ActivateCxObj(keys, state)
  215.   ActivateCxObj(hotkey, TRUE)
  216.   ActivateCxObj(broker, TRUE)
  217. ENDPROC
  218.  
  219.  
  220. ->-----------------------------------------------------------------------------
  221.  
  222. CONST INVALID_PORT = -999
  223.  
  224. PROC open_net(unit, port)
  225.   IF (port < 0) OR (port > $7fff) THEN Throw("NET", INVALID_PORT)
  226.  
  227.   netio := CreateIORequest(devport := CreateMsgPort(), SIZEOF pnrequest)
  228.   netio.msgport       := (netport := CreateMsgPort())
  229.   netio.netsourceport := port
  230.   netio.netdestport   := port
  231.  
  232.   IF open := OpenDevice('pronet.device', unit, netio, 0) THEN Throw("NET", open)
  233. ENDPROC
  234.  
  235.  
  236. PROC close_net()
  237.   IF open = 0 THEN CloseDevice(netio)
  238.  
  239.   IF netport
  240.     clear_port(netport)
  241.     DeleteMsgPort(netport)
  242.   ENDIF
  243.  
  244.   IF netio THEN DeleteIORequest(netio)
  245.  
  246.   IF devport
  247.     clear_port(devport)
  248.     DeleteMsgPort(devport)
  249.   ENDIF
  250. ENDPROC
  251.  
  252. PROC send_data(data, len)
  253.   DEF err
  254.  
  255.   netio.ioreq.command := CMD_WRITE
  256.   netio.data   := data
  257.   netio.length := len
  258.   IF err := DoIO(netio) THEN Throw("NET", err)
  259. ENDPROC
  260.  
  261. -> names for network errors
  262. PROC neterror(err)
  263.   SELECT err
  264.   CASE IOERR_OPENFAIL;          RETURN 'can\at open pronet.device'
  265.   CASE INVALID_PORT;            RETURN 'invalid port number'
  266.   CASE PNDERR_PORTEXISTS;       RETURN 'port already in use'
  267.   CASE PNDERR_DRIVERTROUBLE;    RETURN 'error starting network driver'
  268.   CASE PNDERR_UNIT_NOT_DEFINED; RETURN 'invalid machine number'
  269.   CASE PNDERR_DESTINATION_GONE; RETURN 'network write error'
  270.   DEFAULT; RETURN 'network error'
  271.   ENDSELECT
  272. ENDPROC
  273.  
  274. ->-----------------------------------------------------------------------------
  275.  
  276. -> message-printer for WB and shell
  277. PROC msg(msg, args=NIL)
  278.   IF wbmessage
  279.     EasyRequestArgs(NIL, NEW [20, 0, 'NetKeys', msg, 'Quit'], 0, args)
  280.   ELSE
  281.     Vprintf(msg, args); PutStr('\n')
  282.   ENDIF
  283. ENDPROC
  284.  
  285. -> returns string form of DOS Fault. Can prepend header.
  286. PROC error(error, header=NIL)
  287.   DEF x
  288.   SetStr(x := String((IF header THEN StrLen(header) ELSE 0) + FAULT_MAX + 2),
  289.     Fault(error, header, x, StrMax(x))
  290.   )
  291. ENDPROC x
  292.  
  293. -> removes all messages at a port
  294. PROC clear_port(port)
  295.   DEF m; WHILE m := GetMsg(port) DO ReplyMsg(m)
  296. ENDPROC
  297.